﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Shapes.Misc;
using Microsoft.Xna.Framework.Input;
using Shapes.Geometry;
using Microsoft.Xna.Framework.Graphics;
using Shapes.Misc.Appearance;
using ShapesExtensions;

namespace TestGame.HelperClasses 
{
    /// <summary>
    /// this class contains the jump'n'run hero of the Jump'n'Run Sample
    /// </summary>
    public class JumpNRunPlayer : IDisposable
    {
        const float Gravity = 6;
        const float MoveVelocity = 150;
        const float JumpStrength = 220;

        // the visual of the player
        GeometrySprite _PlayerVisual;

        Vector2 _Velocity = Vector2.Zero;   // the current velocity of the player
        float _Seconds;                     // the seconds of th elast update
        bool _IsCollidingWithBottom;        // true, if the Player hits the bottom

        /// <summary>
        /// Gets / Sets the position of the player
        /// </summary>
        public Vector2 Position { get { return _PlayerVisual.Geometry.Position; } set { _PlayerVisual.Geometry.Position = value; } }
        /// <summary>
        /// Gets the Shape of the player
        /// </summary>
        public Drawing Geometry { get { return _PlayerVisual.Geometry; } }

        public JumpNRunPlayer(TextureGenerator generator)
        {
            // The Player is a ShapeComposition: A Smiley with arms and legs
            ShapeComposition shape = new ShapeComposition(GeometryTemplates.CreateSmiley(16));
            // add feet
            shape.Add(
                new Triangle(new Vector2(14, 32), new Vector2(12, 36), new Vector2(8, 34)),
                ShapeComposeFunction.Add);
            shape.Add(
                new Triangle(new Vector2(18, 32), new Vector2(20, 36), new Vector2(24, 34)),
                ShapeComposeFunction.Add);
            // add arms
            shape.Add(new Ellipse(new Vector2(-2, 19), 3, 3), ShapeComposeFunction.Add);
            shape.Add(new Ellipse(new Vector2(34, 19), 3, 3), ShapeComposeFunction.Add);

            // create player visual object
            _PlayerVisual = new GeometrySprite(shape, generator, new FillColor(Color.Orange)); 


        }

        public void Update(float seconds, GamePadState currentButtons, KeyboardState currentKeys)
        {
            _Seconds = seconds; // we need to save the seconds for collision with a wall
            _Velocity.Y += Gravity; // fall down

            // move
            if (currentKeys.IsKeyDown(Keys.Right) || currentButtons.DPad.Right == ButtonState.Pressed) // move to the right
            {
                _Velocity.X = MoveVelocity;
            }
            else if (currentKeys.IsKeyDown(Keys.Left) || currentButtons.DPad.Left == ButtonState.Pressed) // move to the left
            {
                _Velocity.X = -MoveVelocity;
            }
            else // don't move
            {
                _Velocity.X = 0;
            }

            // Jump!
            if (currentKeys.IsKeyDown(Keys.Space) || currentButtons.IsButtonDown(Buttons.A))
            {
                // but only if the player stays on the ground
                if (_IsCollidingWithBottom)
                    _Velocity.Y -= JumpStrength;
            }

            // calculate the new position
            _PlayerVisual.Geometry.Position += _Velocity * seconds;

            _IsCollidingWithBottom = false;

        }


        // this method let the player stay on the ground 
        // it doesn't matter what shape or drawing the ground is!
        public void CollideWithPlatform(Drawing passiveGeometry)
        {
            // only if the player is above the center of the shape
            // he will be shifted up to the surface
            if (passiveGeometry.Center.Y > _PlayerVisual.Geometry.Center.Y)
            {
                // calculating the Position of the point between the players feet
                Vector2 feetPos = new Vector2(
                    _PlayerVisual.Geometry.Center.X,
                    _PlayerVisual.Geometry.Position.Y + _PlayerVisual.Geometry.Height);

                Vector2 p = passiveGeometry.GetNearestPointOnEdge(feetPos);

                // calculate new position
                _PlayerVisual.Geometry.Position = new Vector2(
                    _PlayerVisual.Geometry.Position.X,  // horizontal position doesn't change
                    _PlayerVisual.Geometry.Position.Y   // the vertical position is shifted up ...
                    - (feetPos.Y                        // by the difference between the feet-position 
                       - p.Y));                         // and the nearest point on the surface

                _Velocity.Y = 0; // don't fall or jump anymore
                _IsCollidingWithBottom = true;
            }
        }
        public void CollideWithWall(Drawing passiveGeometry)
        {
            _Velocity.X *= -1;

            _PlayerVisual.Geometry.Position = new Vector2(
                _PlayerVisual.Geometry.Position.X               // we add to the current vertical position
                + _Velocity.X * _Seconds,                       // the flipped Velocity at the last update
                _PlayerVisual.Geometry.Position.Y);

            _Velocity.X = 0;
        }

        public void Draw(SpriteBatch batch)
        {
            _PlayerVisual.Draw(batch);
        }

        #region IDisposable Member

        public void Dispose()
        {
            this._PlayerVisual.Dispose();
            this._PlayerVisual = null;
        }

        #endregion
    }
}
